// slist.c

#include "mini.h"

//// singal list node
//struct slnode_t
//{
//	void *data;
//    struct slnode_t *next;
//};
//
//// signal list.
//struct slist_t
//{
//    int length;
//    struct slnode_t *head, *tail;
//};
//
//// pointor for special function.
//typedef int (*slist_func_t)(void *data, void *arg);

int slist_init(struct slist_t *sl)
{
    sl->length = 0;
    sl->head = sl->tail = NULL;

    return 0;
}

// append
int slist_append(struct slist_t *sl, void *d)
{
    struct slnode_t *node = malloc(sizeof(struct slnode_t));
    if(node == NULL) {
        return -1;
    }
    node->data = d;

    if(sl->head == NULL) {
        sl->head = sl->tail = node;
        node->next = NULL;
        sl->length++;
    } else {
        sl->tail->next = node;
        node->next = NULL;
        sl->tail = node;
        sl->length++;
    }

    return 0;
}

// insert
int slist_insert(struct slist_t *sl, void *d1, void *d2)
{
    struct slnode_t *p = slist_find(sl, d1);
    if(p == NULL) {
        return -1;
    }

    struct slnode_t *node = malloc(sizeof(struct slnode_t));
    if(node == NULL) {
        return -1;
    }
    node->data = d2;

    if(p == sl->tail) {
        p->next = node;
        node->next = NULL;
        sl->tail = node;
        sl->length++;
    } else {
        node->next = p->next;
        p->next = node;
        sl->length++;
    }

    return 0;
}

// delete
int slist_delete(struct slist_t *sl, void *d)
{
    if(sl->head->data == d) {
        struct slnode_t *tmp = sl->head;
        sl->head = sl->head->next;
        free(tmp);
        sl->length--;
    } else if(sl->tail->data == d) {
        struct slnode_t *p = sl->head;
        while(p->next != sl->tail) {
            p = p->next;
        }
        p->next = NULL;
        free(sl->tail);
        sl->tail = p;
        sl->length--;
    } else {
        struct slnode_t *p = sl->head;
        while(p != NULL && p->next != NULL) {
            if(p->next->data == d) {
                struct slnode_t *tmp = p->next;
                p->next = p->next->next;
                free(tmp);
                sl->length--;
                break;
            } else {
                p = p->next;
            }
        }
    }

    return 0;
}

// length
int slist_length(struct slist_t *sl)
{
    return sl->length;
}

// find
struct slnode_t *slist_find(struct slist_t *sl, void *d)
{
    for(struct slnode_t *p = sl->head; p!=NULL; p=p->next) {
        if(p->data == d) {
            return p;
        }
    }

    return NULL;
}

// foreach
int slist_foreach(struct slist_t *sl, slist_func_t func, void *arg)
{
    struct slnode_t *p = sl->head;

    while(p) {
        func(p->data, arg);
        p = p->next;
    }

    return 0;
}

// slist_clear
int slist_clear(struct slist_t *sl)
{
    struct slnode_t *p;

    while(sl->head) {
        p = sl->head;
        sl->head = sl->head->next;
        free(p);
    }

    return 0;
}
